
/** lock.d - 
  Written in the D programming language 1.0

Authors:	Wei Li <oldrev@gmail.com>
Copyright:	Copyright (c) 2007 by Wei Li.
License:	BSD
 */

module dotmars.threading.mutex;

import dotmars.threading.lock;
import dotmars.threading.except;

version(Posix) 
{
	import dotmars.platform.posix.pthread;

	final class Mutex : Lockable
	{
		alias pthread_mutex_t Handle;

		private bool m_closed;
		private Handle m_handle;

		public this()
		{
			int r = pthread_mutex_init(&m_handle, null);
			if(r != 0)
				throw new ThreadResourceException("Failed to initialize mutex");
			m_closed = false;
		}

		public ~this()
		{
			close();
		}

		public override void lock()
		{
			int r = pthread_mutex_lock(&m_handle);
			if(r != 0)
				throw new LockException("Failed to wait for mutex");
		}

		public override bool lock(uint timeout)
		{
			timespec ts;
			ts.tv_sec = timeout / 1000;
			ts.tv_nsec = (timeout * 1000) - (ts.tv_sec * 1000 * 1000)  ;
			return pthread_mutex_timedlock(&m_handle, &ts) == 0;
		}

		public override void unlock()
		{
			int r = pthread_mutex_unlock(&m_handle);
			if(r != 0)
				throw new LockException("Failed to release mutex");

		}

		public override bool tryLock()
		{
			return pthread_mutex_trylock(&m_handle) == 0;
		}

		public override void close()
		{
			if(isClosed) return;

			pthread_mutex_destroy(&m_handle); //do no throw exceptions in dtor
			m_closed = true;
		}

		private bool isClosed()
		{
			return m_closed;
		}
	}

}



version(Windows) 
{

	import dotmars.platform.windows.core;

	final class Mutex : Lockable
	{
		alias HANDLE	Handle;
		private Handle m_handle;

		public this()
		{
			m_handle = CreateMutexW(null, FALSE, null);
			if(m_handle is null)
				throw new ThreadResourceException("Failed to initialize mutex");
		}

		public ~this()
		{
			close();
		}

		public override void lock()
		{
			uint r = WaitForSingleObject(m_handle, INFINITE);
			if(r != WAIT_OBJECT_0)
				throw new LockException("Failed to wait for mutex");
		}

		public override bool lock(uint timeout)
		{
			uint r = WaitForSingleObject(m_handle, timeout * 1000);
			if(r != WAIT_OBJECT_0)
				throw new LockException("Failed to wait for mutex");
		}

		public override bool tryLock()
		{
			return WaitForSingleObject(m_handle, 0) == WAIT_OBJECT_0;
		}

		public override void unlock()
		{
			if(!ReleaseMutex(m_handle))
				throw new LockException("Failed to release mutex");

		}

		public override void close()
		{
			if(isClosed) return;

			CloseHandle(m_handle);
			m_handle = null;
		}

		private bool isClosed()
		{
			return m_handle == null;
		}
	}

}

/+
class FastMutex : IDisposable, ILockable
{
}
+/
